﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lidgren.Network;
using Lidgren.Network.Xna;
using Microsoft.Xna.Framework;

namespace Engine.Networking.Client
{
    public class GameClient : GameComponent
    {
        public delegate void DataRecievedEventHandler(NetIncomingMessage _msg);
        public event DataRecievedEventHandler OnDataRecieved;
        
        NetClient client;

        bool writingStartet = false;
        NetOutgoingMessage om;
        public NetConnectionStatus Status { get { return client.ConnectionStatus; } }

        public GameClient(string _appID, Game _game) : base (_game)
        {
            NetPeerConfiguration config = new NetPeerConfiguration(_appID);
            config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);

            client = new NetClient(config);
            client.Start();
        }

        public override void Update(GameTime gameTime)
        {
            ReadMessages();
 	        base.Update(gameTime);
        }

        public void Start()
        {
            client.Start();
        }

        public void Shutdown(string _msg)
        {
            client.Shutdown(_msg);
        }

        public void ConnectLocally(int _port)
        {
            client.DiscoverLocalPeers(_port);
        }

        public void Connect(string _ip, int _port)
        {
            client.DiscoverKnownPeer(_ip, _port);
        }

        public void StartWritingMessage()
        {
            if(!writingStartet)
            {
                om = client.CreateMessage();
                writingStartet = true;
            }
        }

        #region Message Writing

        public void Write(int _value)
        {
            if (writingStartet)
            {
                om.Write(_value);
            }
        }

        public void Write(bool _value)
        {
            if (writingStartet)
            {
                om.Write(_value);
            }
        }

        public void Write(float _value)
        {
            if (writingStartet)
            {
                om.Write(_value);
            }
        }

        public void Write(string _value)
        {
            if (writingStartet)
            {
                om.Write(_value);
            }
        }

        public void Write(long _value)
        {
            if (writingStartet)
            {
                om.Write(_value);
            }
        }

        public void Write(Vector2 _value)
        {
            if (writingStartet)
            {
                XNAExtensions.Write(om, _value);
            }
        }

        public void Write(Point _value)
        {
            if (writingStartet)
            {
                XNAExtensions.Write(om, _value);
            }
        }

        #endregion

        public void SendMessage(NetDeliveryMethod _method = NetDeliveryMethod.UnreliableSequenced)
        {
            if (writingStartet)
            {
                client.SendMessage(om, _method);
                writingStartet = false;
            }
        }

        public void ReadMessages()
        {
            NetIncomingMessage msg;
            while ((msg = client.ReadMessage()) != null)
            {
                switch (msg.MessageType)
                {
                    case NetIncomingMessageType.DiscoveryResponse:
                        // just connect to first server discovered
                        client.Connect(msg.SenderEndpoint);
                        Console.WriteLine("Connected to " + msg.SenderEndpoint.ToString());
                        break;
                    case NetIncomingMessageType.ConnectionApproval:
                        client.Connect(msg.SenderEndpoint);
                        Console.WriteLine("Connected to " + msg.SenderEndpoint.ToString());
                        break;
                    case NetIncomingMessageType.ErrorMessage:
                        Console.WriteLine(msg.ReadString());
                        break;
                    case NetIncomingMessageType.Data:
                        if (OnDataRecieved != null)
                            OnDataRecieved(msg);
                        break;
                }
            }
        }
    }
}
